package com.gjs.common.filter;

import cn.hutool.json.JSONUtil;
import cn.hutool.jwt.JWT;
import cn.hutool.jwt.JWTUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.gjs.common.manager.response.RspBody;
import com.gjs.common.pojo.dto.user.UserInfoDTO;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Slf4j
public class JWTAuthorizationFilter extends BasicAuthenticationFilter {

    @Setter
    private String secretKey;

    @Setter
    private String cacheKey;

    @Autowired
    private RedisOperations<String,Object> redisUtil;

    public JWTAuthorizationFilter(AuthenticationManager authenticationManager) {
        super(authenticationManager);
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain chain) throws IOException, ServletException {
        try {
            String token = request.getHeader("token");
            if (StringUtils.isEmpty(token)) {
                chain.doFilter(request, response);
                return;
            }

            Assert.isTrue(JWTUtil.verify(token, secretKey.getBytes()),"TOKEN校验失败");

            // 解析TOKEN
            final JWT jwt = JWTUtil.parseToken(token);
            // 从token中解析出用户账号
            String userSn = jwt.getPayload("userSn").toString();
            String authenticationJsonStr = (String) redisUtil.opsForValue().get(cacheKey + userSn);

            Assert.notNull(authenticationJsonStr,"TOKEN不存在或已失效");

            JSONObject authenticationJson = JSON.parseObject(authenticationJsonStr);
            // 从JSON中解析出用户信息
            UserInfoDTO userInfoDTO = authenticationJson.getObject("details",UserInfoDTO.class);
            // 从JSON中解析出用户权限
            List<GrantedAuthority> authorities = new ArrayList<>();
            try {
                List<Map<String,String>> authorityList = authenticationJson.getObject("authorities", ArrayList.class);
                if(authorityList != null && !authorityList.isEmpty()){
                    for (Map<String,String> authorityMap : authorityList) {
                        authorities.add(new SimpleGrantedAuthority(authorityMap.get("authority")));
                    }
                }
            }catch (Exception e){
                authorities = AuthorityUtils.NO_AUTHORITIES;
            }
            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userInfoDTO,userInfoDTO.getUserSn(),authorities);
            // 重新注入UsernamePasswordAuthenticationToken对象到security
            SecurityContextHolder.getContext().setAuthentication(authenticationToken);
        } catch (Exception e) {
            response.setContentType("application/json;charset=UTF-8");
            response.getWriter().write(JSONUtil.toJsonStr(RspBody.forbid(e.getMessage())));
            return;
        }
        super.doFilterInternal(request, response, chain);
    }
}
